﻿/**
 ******************************************************************************
 * @file           : bsp_spi_config.h
 * @brief          : SPI Hardware Configuration File (STM32F4xx)
 ******************************************************************************
 * @attention
 *
 * SPI硬件配置文件
 * 用户通过修改宏定义的数值来配置SPI参数（配置驱动设计）
 *
 * STM32F4xx版本
 *
 ******************************************************************************
 */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __BSP_SPI_CONFIG_H
#define __BSP_SPI_CONFIG_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/

/* ============================================================================ */
/*                       日志系统配置（改这里的数字）                             */
/* ============================================================================ */
/* 日志后端选择：1=EasyLogger, 2=printf, 0=关闭 */
#define SPI_USE_LOG     1

/* 根据配置自动定义日志宏 */
#if (SPI_USE_LOG == 1)
    /* 使用EasyLogger */
    #ifndef LOG_TAG
        #define LOG_TAG    "SPI"
    #endif
    #include "elog.h"
    
#elif (SPI_USE_LOG == 2)
    /* 使用printf */
    #include <stdio.h>
    #define log_i(fmt, ...)     printf("[INFO] " fmt "\r\n", ##__VA_ARGS__)
    #define log_w(fmt, ...)     printf("[WARN] " fmt "\r\n", ##__VA_ARGS__)
    #define log_e(fmt, ...)     printf("[ERROR] " fmt "\r\n", ##__VA_ARGS__)
    #define log_d(fmt, ...)     printf("[DEBUG] " fmt "\r\n", ##__VA_ARGS__)
    
#else
    /* 关闭日志 */
    #define log_i(fmt, ...)
    #define log_w(fmt, ...)
    #define log_e(fmt, ...)
    #define log_d(fmt, ...)
#endif

/* ============================================================================ */
/*                          用户配置区（修改这里的数字）                          */
/* ============================================================================ */

/**
 * SPI外设选择
 * 
 * 可选值：
 *   1 = SPI1（APB2总线，最高42MHz @ 84MHz APB2）【推荐】
 *   2 = SPI2（APB1总线，最高21MHz @ 42MHz APB1）
 *   3 = SPI3（APB1总线，最高21MHz @ 42MHz APB1）
 * 
 * 注意：STM32F4还有SPI4/5/6，本驱动暂未支持
 */
#define SPI_SELECT_NUM          1       /*!< 选择使用的SPI号 */

/**
 * 引脚重映射模式
 * 
 * STM32F4xx使用GPIO AF（复用功能），不需要重映射
 * 
 * SPI1:
 *   0 = PA5(SCK), PA6(MISO), PA7(MOSI)  - 标准引脚
 *   1 = PB3(SCK), PB4(MISO), PB5(MOSI)  - 备用引脚
 * 
 * SPI2:
 *   0 = PB10(SCK), PB14(MISO), PB15(MOSI) - 标准引脚
 *   1 = PB13(SCK), PB14(MISO), PB15(MOSI) - 备用引脚
 * 
 * SPI3:
 *   0 = PB3(SCK), PB4(MISO), PB5(MOSI)   - 标准引脚
 *   1 = PC10(SCK), PC11(MISO), PC12(MOSI) - 备用引脚
 */
#define SPI_REMAP_MODE          0       /*!< 引脚重映射模式 */

/* CS片选引脚（软件控制，可任意GPIO） */
#define SPI_CS_GPIO_PORT                GPIOA
#define SPI_CS_GPIO_PIN                 GPIO_PIN_4

/**
 * SPI模式选择
 * 
 * 可选值：
 *   0 = Mode 0 (CPOL=0, CPHA=0) - W25Qxx/SD卡常用
 *   1 = Mode 1 (CPOL=0, CPHA=1)
 *   2 = Mode 2 (CPOL=1, CPHA=0)
 *   3 = Mode 3 (CPOL=1, CPHA=1) - W25Qxx也支持
 */
#define SPI_MODE_SELECT         0       /*!< SPI模式 */

/**
 * SPI波特率分频
 * 
 * 可选值：2, 4, 8, 16, 32, 64, 128, 256
 * 
 * 计算公式（以84MHz APB2为例）：
 * SPI1（APB2, 84MHz）:
 *   /2=42MHz, /4=21MHz, /8=10.5MHz, /16=5.25MHz, /32=2.625MHz...
 * SPI2/3（APB1, 42MHz）:
 *   /2=21MHz, /4=10.5MHz, /8=5.25MHz, /16=2.625MHz, /32=1.3125MHz...
 */
#define SPI_BAUDRATE_DIV        8       /*!< 波特率分频 */

/**
 * 数据位宽
 * 
 * 可选值：
 *   8  = 8位数据（常用）
 *   16 = 16位数据
 */
#define SPI_DATA_SIZE           8       /*!< 数据位宽 */

/**
 * SPI方向模式
 * 
 * 可选值：
 *   0 = 双线全双工（MISO+MOSI，标准模式）
 *   1 = 单线发送（仅MOSI，用于LCD等只写设备）
 *   2 = 双线接收（仅MISO，很少使用）
 * 
 * 说明：
 *   - 单线模式：只初始化MOSI引脚，不初始化MISO
 *   - 双线模式：初始化MOSI和MISO引脚
 */
#define SPI_DIRECTION_MODE      0       /*!< 方向模式：0=双线，1=单线发送，2=双线接收 */

/**
 * 传输顺序
 * 
 * 可选值：
 *   0 = MSB先行（常用）
 *   1 = LSB先行
 */
#define SPI_FIRSTBIT            0       /*!< 传输顺序：0=MSB, 1=LSB */

/* 超时时间（毫秒） */
#define SPI_TIMEOUT_MS          100

/**
 * DMA功能使能
 * 
 * 可选值：
 *   0 = 禁用DMA（默认）
 *   1 = 使能DMA（推荐用于大数据量传输）
 */
#define SPI_USE_DMA             0       /*!< DMA功能使能 */

/* ============================================================================ */
/*            自动配置区（用户不应修改下面的内容）                                */
/* ============================================================================ */

/* SPI外设选择 */
#if (SPI_SELECT_NUM == 1)
    #define SPI_SPIx                        SPI1
    #define SPI_SPIx_CLK_ENABLE()           __HAL_RCC_SPI1_CLK_ENABLE()
    #define SPI_SPIx_IRQn                   SPI1_IRQn
    #define SPI_IRQHandler_NAME             SPI1_IRQHandler
#elif (SPI_SELECT_NUM == 2)
    #define SPI_SPIx                        SPI2
    #define SPI_SPIx_CLK_ENABLE()           __HAL_RCC_SPI2_CLK_ENABLE()
    #define SPI_SPIx_IRQn                   SPI2_IRQn
    #define SPI_IRQHandler_NAME             SPI2_IRQHandler
#elif (SPI_SELECT_NUM == 3)
    #define SPI_SPIx                        SPI3
    #define SPI_SPIx_CLK_ENABLE()           __HAL_RCC_SPI3_CLK_ENABLE()
    #define SPI_SPIx_IRQn                   SPI3_IRQn
    #define SPI_IRQHandler_NAME             SPI3_IRQHandler
#else
    #error "SPI_SELECT_NUM必须为1、2或3"
#endif

/* 引脚配置（STM32F4xx使用GPIO AF复用功能） */
#if (SPI_SELECT_NUM == 1)
    #if (SPI_REMAP_MODE == 0)
        /* SPI1标准引脚：PA5/6/7 */
        #define SPI_SCK_GPIO_PORT           GPIOA
        #define SPI_SCK_GPIO_PIN            GPIO_PIN_5
        #define SPI_SCK_AF                  GPIO_AF5_SPI1
        
        #define SPI_MISO_GPIO_PORT          GPIOA
        #define SPI_MISO_GPIO_PIN           GPIO_PIN_6
        #define SPI_MISO_AF                 GPIO_AF5_SPI1
        
        #define SPI_MOSI_GPIO_PORT          GPIOA
        #define SPI_MOSI_GPIO_PIN           GPIO_PIN_7
        #define SPI_MOSI_AF                 GPIO_AF5_SPI1
    #elif (SPI_REMAP_MODE == 1)
        /* SPI1备用引脚：PB3/4/5 */
        #define SPI_SCK_GPIO_PORT           GPIOB
        #define SPI_SCK_GPIO_PIN            GPIO_PIN_3
        #define SPI_SCK_AF                  GPIO_AF5_SPI1
        
        #define SPI_MISO_GPIO_PORT          GPIOB
        #define SPI_MISO_GPIO_PIN           GPIO_PIN_4
        #define SPI_MISO_AF                 GPIO_AF5_SPI1
        
        #define SPI_MOSI_GPIO_PORT          GPIOB
        #define SPI_MOSI_GPIO_PIN           GPIO_PIN_5
        #define SPI_MOSI_AF                 GPIO_AF5_SPI1
    #else
        #error "SPI1 REMAP_MODE必须为0或1"
    #endif
    
#elif (SPI_SELECT_NUM == 2)
    #if (SPI_REMAP_MODE == 0)
        /* SPI2标准引脚：PB10/14/15 */
        #define SPI_SCK_GPIO_PORT           GPIOB
        #define SPI_SCK_GPIO_PIN            GPIO_PIN_10
        #define SPI_SCK_AF                  GPIO_AF5_SPI2
        
        #define SPI_MISO_GPIO_PORT          GPIOB
        #define SPI_MISO_GPIO_PIN           GPIO_PIN_14
        #define SPI_MISO_AF                 GPIO_AF5_SPI2
        
        #define SPI_MOSI_GPIO_PORT          GPIOB
        #define SPI_MOSI_GPIO_PIN           GPIO_PIN_15
        #define SPI_MOSI_AF                 GPIO_AF5_SPI2
    #elif (SPI_REMAP_MODE == 1)
        /* SPI2备用引脚：PB13/14/15 */
        #define SPI_SCK_GPIO_PORT           GPIOB
        #define SPI_SCK_GPIO_PIN            GPIO_PIN_13
        #define SPI_SCK_AF                  GPIO_AF5_SPI2
        
        #define SPI_MISO_GPIO_PORT          GPIOB
        #define SPI_MISO_GPIO_PIN           GPIO_PIN_14
        #define SPI_MISO_AF                 GPIO_AF5_SPI2
        
        #define SPI_MOSI_GPIO_PORT          GPIOB
        #define SPI_MOSI_GPIO_PIN           GPIO_PIN_15
        #define SPI_MOSI_AF                 GPIO_AF5_SPI2
    #else
        #error "SPI2 REMAP_MODE必须为0或1"
    #endif
    
#elif (SPI_SELECT_NUM == 3)
    #if (SPI_REMAP_MODE == 0)
        /* SPI3标准引脚：PB3/4/5 */
        #define SPI_SCK_GPIO_PORT           GPIOB
        #define SPI_SCK_GPIO_PIN            GPIO_PIN_3
        #define SPI_SCK_AF                  GPIO_AF6_SPI3
        
        #define SPI_MISO_GPIO_PORT          GPIOB
        #define SPI_MISO_GPIO_PIN           GPIO_PIN_4
        #define SPI_MISO_AF                 GPIO_AF6_SPI3
        
        #define SPI_MOSI_GPIO_PORT          GPIOB
        #define SPI_MOSI_GPIO_PIN           GPIO_PIN_5
        #define SPI_MOSI_AF                 GPIO_AF6_SPI3
    #elif (SPI_REMAP_MODE == 1)
        /* SPI3备用引脚：PC10/11/12 */
        #define SPI_SCK_GPIO_PORT           GPIOC
        #define SPI_SCK_GPIO_PIN            GPIO_PIN_10
        #define SPI_SCK_AF                  GPIO_AF6_SPI3
        
        #define SPI_MISO_GPIO_PORT          GPIOC
        #define SPI_MISO_GPIO_PIN           GPIO_PIN_11
        #define SPI_MISO_AF                 GPIO_AF6_SPI3
        
        #define SPI_MOSI_GPIO_PORT          GPIOC
        #define SPI_MOSI_GPIO_PIN           GPIO_PIN_12
        #define SPI_MOSI_AF                 GPIO_AF6_SPI3
    #else
        #error "SPI3 REMAP_MODE必须为0或1"
    #endif
#endif

/* GPIO时钟使能宏 */
#define SPI_SCK_GPIO_CLK_ENABLE()       do{ \
    if(SPI_SCK_GPIO_PORT == GPIOA) __HAL_RCC_GPIOA_CLK_ENABLE(); \
    else if(SPI_SCK_GPIO_PORT == GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE(); \
    else if(SPI_SCK_GPIO_PORT == GPIOC) __HAL_RCC_GPIOC_CLK_ENABLE(); \
}while(0)

#define SPI_MISO_GPIO_CLK_ENABLE()      do{ \
    if(SPI_MISO_GPIO_PORT == GPIOA) __HAL_RCC_GPIOA_CLK_ENABLE(); \
    else if(SPI_MISO_GPIO_PORT == GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE(); \
    else if(SPI_MISO_GPIO_PORT == GPIOC) __HAL_RCC_GPIOC_CLK_ENABLE(); \
}while(0)

#define SPI_MOSI_GPIO_CLK_ENABLE()      do{ \
    if(SPI_MOSI_GPIO_PORT == GPIOA) __HAL_RCC_GPIOA_CLK_ENABLE(); \
    else if(SPI_MOSI_GPIO_PORT == GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE(); \
    else if(SPI_MOSI_GPIO_PORT == GPIOC) __HAL_RCC_GPIOC_CLK_ENABLE(); \
}while(0)

#define SPI_CS_GPIO_CLK_ENABLE()        do{ \
    if(SPI_CS_GPIO_PORT == GPIOA) __HAL_RCC_GPIOA_CLK_ENABLE(); \
    else if(SPI_CS_GPIO_PORT == GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE(); \
    else if(SPI_CS_GPIO_PORT == GPIOC) __HAL_RCC_GPIOC_CLK_ENABLE(); \
}while(0)

/* SPI模式自动转换 */
#if (SPI_MODE_SELECT == 0)
    #define SPI_CPOL                        SPI_POLARITY_LOW
    #define SPI_CPHA                        SPI_PHASE_1EDGE
#elif (SPI_MODE_SELECT == 1)
    #define SPI_CPOL                        SPI_POLARITY_LOW
    #define SPI_CPHA                        SPI_PHASE_2EDGE
#elif (SPI_MODE_SELECT == 2)
    #define SPI_CPOL                        SPI_POLARITY_HIGH
    #define SPI_CPHA                        SPI_PHASE_1EDGE
#elif (SPI_MODE_SELECT == 3)
    #define SPI_CPOL                        SPI_POLARITY_HIGH
    #define SPI_CPHA                        SPI_PHASE_2EDGE
#else
    #error "SPI_MODE_SELECT必须为0、1、2或3"
#endif

/* 方向模式自动转换 */
#if (SPI_DIRECTION_MODE == 0)
    #define SPI_DIRECTION                   SPI_DIRECTION_2LINES            /* 双线全双工 */
#elif (SPI_DIRECTION_MODE == 1)
    #define SPI_DIRECTION                   SPI_DIRECTION_1LINE             /* 单线发送（仅MOSI） */
#elif (SPI_DIRECTION_MODE == 2)
    #define SPI_DIRECTION                   SPI_DIRECTION_2LINES_RXONLY     /* 双线接收（仅MISO） */
#else
    #error "SPI_DIRECTION_MODE必须为0（双线）、1（单线）或2（接收）"
#endif

/* 波特率自动转换 */
#if (SPI_BAUDRATE_DIV == 2)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_2
#elif (SPI_BAUDRATE_DIV == 4)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_4
#elif (SPI_BAUDRATE_DIV == 8)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_8
#elif (SPI_BAUDRATE_DIV == 16)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_16
#elif (SPI_BAUDRATE_DIV == 32)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_32
#elif (SPI_BAUDRATE_DIV == 64)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_64
#elif (SPI_BAUDRATE_DIV == 128)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_128
#elif (SPI_BAUDRATE_DIV == 256)
    #define SPI_BAUDRATE_PRESCALER          SPI_BAUDRATEPRESCALER_256
#else
    #error "SPI_BAUDRATE_DIV必须为2、4、8、16、32、64、128或256"
#endif

/* 数据位宽自动转换 */
#if (SPI_DATA_SIZE == 8)
    #define SPI_DATASIZE                    SPI_DATASIZE_8BIT
#elif (SPI_DATA_SIZE == 16)
    #define SPI_DATASIZE                    SPI_DATASIZE_16BIT
#else
    #error "SPI_DATA_SIZE必须为8或16"
#endif

/* 传输顺序自动转换 */
#if (SPI_FIRSTBIT == 0)
    #define SPI_FIRST_BIT                   SPI_FIRSTBIT_MSB
#elif (SPI_FIRSTBIT == 1)
    #define SPI_FIRST_BIT                   SPI_FIRSTBIT_LSB
#else
    #error "SPI_FIRSTBIT必须为0（MSB）或1（LSB）"
#endif

/* DMA配置（STM32F4xx使用DMA Stream） */
#if (SPI_USE_DMA == 1)
    #if (SPI_SELECT_NUM == 1)
        /* SPI1_TX: DMA2 Stream3 Channel3 或 Stream5 Channel3 */
        #define SPI_DMA_TX                      DMA2
        #define SPI_DMA_TX_STREAM               DMA2_Stream3
        #define SPI_DMA_TX_CHANNEL              DMA_CHANNEL_3
        #define SPI_DMA_TX_IRQn                 DMA2_Stream3_IRQn
        #define SPI_DMA_TX_CLK_ENABLE()         __HAL_RCC_DMA2_CLK_ENABLE()
    #elif (SPI_SELECT_NUM == 2)
        /* SPI2_TX: DMA1 Stream4 Channel0 */
        #define SPI_DMA_TX                      DMA1
        #define SPI_DMA_TX_STREAM               DMA1_Stream4
        #define SPI_DMA_TX_CHANNEL              DMA_CHANNEL_0
        #define SPI_DMA_TX_IRQn                 DMA1_Stream4_IRQn
        #define SPI_DMA_TX_CLK_ENABLE()         __HAL_RCC_DMA1_CLK_ENABLE()
    #elif (SPI_SELECT_NUM == 3)
        /* SPI3_TX: DMA1 Stream5 Channel0 或 Stream7 Channel0 */
        #define SPI_DMA_TX                      DMA1
        #define SPI_DMA_TX_STREAM               DMA1_Stream5
        #define SPI_DMA_TX_CHANNEL              DMA_CHANNEL_0
        #define SPI_DMA_TX_IRQn                 DMA1_Stream5_IRQn
        #define SPI_DMA_TX_CLK_ENABLE()         __HAL_RCC_DMA1_CLK_ENABLE()
    #endif
#endif

/* CS控制宏 */
#define SPI_CS_LOW()                    HAL_GPIO_WritePin(SPI_CS_GPIO_PORT, SPI_CS_GPIO_PIN, GPIO_PIN_RESET)
#define SPI_CS_HIGH()                   HAL_GPIO_WritePin(SPI_CS_GPIO_PORT, SPI_CS_GPIO_PIN, GPIO_PIN_SET)

/* Exported macro ------------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/

#ifdef __cplusplus
}
#endif

#endif /* __BSP_SPI_CONFIG_H */
